﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CarbonExchange.Bll;
using CarbonExchange.Bll.Exceptions;

namespace CarbonExchange.Tests
{
    [TestClass]
    public class QuestionTests : BaseTest
    {
        [TestMethod]
        public void Question_GetById_WithIncorretID_ReturnsNull()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            Assert.IsNull(tmpFactory.GetById(int.MaxValue));
        }

        [TestMethod]
        public void Question_GetById_WithCorretID_ReturnsNotNull()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            Assert.IsNotNull(tmpFactory.GetById(_TestQuestions[2].Id));
        }

        [TestMethod]
        public void Question_GetById_PopulatesCorrectly()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = tmpFactory.GetById(_TestQuestions[3].Id);
            Assert.IsNotNull(tmp);
            Assert.AreEqual(_TestQuestions[3].Id, tmp.Id);
            Assert.AreEqual(_TestQuestions[3].Created.ToLocalTime(), tmp.Created);
            Assert.AreEqual(_TestQuestions[3].QuestionName, tmp.Name);
            Assert.AreEqual(_TestQuestions[3].Type, (byte)tmp.QuestionType);
            Assert.AreEqual(_TestQuestions[3].Section.Name, tmp.SectionName);
            Assert.AreEqual(_TestQuestions[3].SectionId, tmp.SectionId);
        }

        [TestMethod]
        public void Question_GetByAll_ReturnsList()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = tmpFactory.GetAll();
            Assert.IsNotNull(tmp);
            Assert.AreEqual(_TestQuestions.Count, tmp.Count());
        }

        [TestMethod]
        public void Question_GetByAll_PopulatesCorrectly()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = tmpFactory.GetAll();
            Assert.IsNotNull(tmp);
            Assert.AreEqual(_TestQuestions.Count, tmp.Count());
            for (int i = 0; i < _TestQuestions.Count; i++)
            {
                Assert.AreEqual(_TestQuestions[i].Id, tmp[i].Id);
                Assert.AreEqual(_TestQuestions[i].Created.ToLocalTime(), tmp[i].Created);
                Assert.AreEqual(_TestQuestions[i].QuestionName, tmp[i].Name);
                Assert.AreEqual(_TestQuestions[i].Type, (byte)tmp[i].QuestionType);
                Assert.AreEqual(_TestQuestions[i].Section.Name, tmp[i].SectionName);
                Assert.AreEqual(_TestQuestions[i].SectionId, tmp[1].SectionId);
            }
        }

        [TestMethod]
        public void Question_UpdateOne()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = tmpFactory.GetById(_TestQuestions[0].Id);
            Assert.IsNotNull(tmp);

            tmp.Name = "Update Test";
            tmp.QuestionType = QuestionTextConfiguration.QuestionTypes.Electricity;
            tmp.SectionId = _TestSections[1].Id;

            tmpFactory.Save(tmp);

            Assert.AreEqual(_TestQuestions[0].Id, tmp.Id);
            Assert.AreEqual(_TestQuestions[0].Created.ToLocalTime(), tmp.Created);
            Assert.AreEqual("Update Test", tmp.Name);
            Assert.AreEqual(QuestionTextConfiguration.QuestionTypes.Electricity, tmp.QuestionType);
            Assert.AreEqual(_TestSections[1].Id, tmp.SectionId);
            Assert.AreEqual(_TestSections[1].Name, tmp.SectionName);

            var tmp2 = tmpFactory.GetById(_TestQuestions[0].Id);

            Assert.AreEqual(tmp.Id, tmp2.Id);
            Assert.AreEqual(tmp.Created, tmp2.Created);
            Assert.AreEqual(tmp.Name, tmp2.Name);
            Assert.AreEqual(tmp.QuestionType, tmp2.QuestionType);
            Assert.AreEqual(tmp.SectionId, tmp2.SectionId);
            Assert.AreEqual(tmp.SectionName, tmp2.SectionName);
        }

        [TestMethod]
        public void Question_UpdateMany()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = tmpFactory.GetAll();
            Assert.IsNotNull(tmp);
            Assert.AreEqual(_TestQuestions.Count, tmp.Count);
            for (int i = 0; i < tmp.Count; i++)
            {
                tmp[i].Name = string.Format("Update Test {0}", i);
                tmp[i].QuestionType = QuestionTextConfiguration.QuestionTypes.Electricity;
                tmp[i].SectionId = _TestSections[2].Id;
            }

            tmpFactory.Save(tmp);
            for (int i = 0; i < tmp.Count; i++)
            {
                Assert.AreEqual(_TestQuestions[i].Id, tmp[i].Id);
                Assert.AreEqual(_TestQuestions[i].Created.ToLocalTime(), tmp[i].Created);
                Assert.AreEqual(string.Format("Update Test {0}", i), tmp[i].Name);
                Assert.AreEqual(QuestionTextConfiguration.QuestionTypes.Electricity, tmp[i].QuestionType);
                Assert.AreEqual(_TestSections[2].Id, tmp[i].SectionId);
                Assert.AreEqual(_TestSections[2].Name, tmp[i].SectionName);
            }

            tmp = tmpFactory.GetAll();
            for (int i = 0; i < tmp.Count; i++)
            {
                Assert.AreEqual(_TestQuestions[i].Id, tmp[i].Id);
                Assert.AreEqual(_TestQuestions[i].Created.ToLocalTime(), tmp[i].Created);
                Assert.AreEqual(string.Format("Update Test {0}", i), tmp[i].Name);
                Assert.AreEqual(QuestionTextConfiguration.QuestionTypes.Electricity, tmp[i].QuestionType);
                Assert.AreEqual(_TestSections[2].Id, tmp[i].SectionId);
                Assert.AreEqual(_TestSections[2].Name, tmp[i].SectionName);
            }
        }

        [TestMethod]
        public void Question_Delete_One()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = tmpFactory.GetById(_TestQuestions[0].Id);
            Assert.IsNotNull(tmp);
            tmpFactory.Delete(tmp);
            tmp = tmpFactory.GetById(_TestQuestions[0].Id);
            Assert.IsNull(tmp);
            Assert.AreEqual(_TestQuestions.Count - 1, tmpFactory.GetAll().Count());
        }

        [TestMethod]
        public void Question_Delete_Many()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = tmpFactory.GetAll().Skip(1);
            Assert.IsNotNull(tmp);
            tmpFactory.Delete(tmp);
            Assert.AreEqual(1, tmpFactory.GetAll().Count());
        }

        [TestMethod]
        public void Question_Insert_One()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = new Question();
            tmp.QuestionType = QuestionTextConfiguration.QuestionTypes.Electricity;
            tmp.Name = "Insert Test";
            tmp.SectionId = _TestSections[1].Id;
            DateTime expected = DateTime.Now;
            tmpFactory.Save(tmp);
            int id = tmp.Id;
            Assert.IsTrue(tmp.Id > 0);
            Assert.AreEqual(QuestionTextConfiguration.QuestionTypes.Electricity, tmp.QuestionType);
            Assert.AreEqual("Insert Test", tmp.Name);
            Assert.IsTrue(expected - tmp.Created < TimeSpan.FromSeconds(1));
            Assert.AreEqual(_TestSections[1].Id, tmp.SectionId);
            Assert.AreEqual(_TestSections[1].Name, tmp.SectionName);

            var tmp2 = tmpFactory.GetById(id);

            Assert.IsNotNull(tmp2);
            Assert.AreEqual(tmp.Id, tmp2.Id);
            Assert.AreEqual(tmp.QuestionType, tmp2.QuestionType);
            Assert.AreEqual(tmp.Name, tmp2.Name);
            Assert.AreEqual(tmp.Created, tmp2.Created);
            Assert.AreEqual(tmp.SectionId, tmp2.SectionId);
            Assert.AreEqual(tmp.SectionName, tmp2.SectionName);
        }

        [TestMethod]
        public void Question_Insert_Many()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            int count = 3;

            var tmp = new Question[count];
            for (int i = 0; i < count; i++)
            {
                tmp[i] = new Question();
                tmp[i].QuestionType = QuestionTextConfiguration.QuestionTypes.Electricity;
                tmp[i].Name = "Insert Test {0}".Format(i);
                tmp[i].SectionId = _TestSections[1].Id;
            }
            DateTime expected = DateTime.Now;
            tmpFactory.Save(tmp);
            for (int i = 0; i < count; i++)
            {
                int id = tmp[i].Id;
                Assert.IsTrue(tmp[i].Id > 0);
                Assert.AreEqual(QuestionTextConfiguration.QuestionTypes.Electricity, tmp[i].QuestionType);
                Assert.AreEqual("Insert Test {0}".Format(i), tmp[i].Name);
                Assert.IsTrue(expected - tmp[i].Created < TimeSpan.FromSeconds(1));
                Assert.AreEqual(_TestSections[1].Id, tmp[i].SectionId);
                Assert.AreEqual(_TestSections[1].Name, tmp[i].SectionName);

                var tmp2 = tmpFactory.GetById(id);

                Assert.IsNotNull(tmp2);
                Assert.AreEqual(tmp[i].Id, tmp2.Id);
                Assert.AreEqual(tmp[i].QuestionType, tmp2.QuestionType);
                Assert.AreEqual(tmp[i].Name, tmp2.Name);
                Assert.AreEqual(tmp[i].Created, tmp2.Created);
                Assert.AreEqual(tmp[i].SectionId, tmp2.SectionId);
                Assert.AreEqual(tmp[i].SectionName, tmp2.SectionName);
            }
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void Question_EmptyName_CausesValidationException()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = new Question();
            tmp.QuestionType = QuestionTextConfiguration.QuestionTypes.Electricity;
            tmpFactory.Save(tmp);
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void Question_EmptyType_CausesValidationException()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = new Question();
            tmp.Name = "Insert Name";
            tmpFactory.Save(tmp);
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void Question_DuplicateName_InsertOne_CausesValidationException()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = new Question();
            tmp.Name = _TestQuestions[0].QuestionName;
            tmp.QuestionType = QuestionTextConfiguration.QuestionTypes.Electricity;
            tmpFactory.Save(tmp);
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void Question_DuplicateName_InsertMany_CausesValidationException()
        {
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            var tmp = new Question[2];
            for(int i = 0; i < tmp.Count(); i++)
            {
                tmp[i] = new Question();
                tmp[i].Name = "DuplicateTest";
                tmp[i].QuestionType = QuestionTextConfiguration.QuestionTypes.Electricity;
            }
            tmpFactory.Save(tmp);
        }

        [TestMethod]
        public void Question_GetAllBySectionId_ReturnsCorrectList()
        {
            _TestQuestions[0].Section = _TestSections[1];
            _TestQuestions[1].Section = _TestSections[1];
            _TestQuestions[2].Section = _TestSections[1];
            _TestQuestions[3].Section = _TestSections[2];
            _Context.SubmitChanges();
            QuestionFactory tmpFactory = new QuestionFactory(_Context);
            Assert.AreEqual(0, tmpFactory.GetAllBySectionId(_TestSections[0].Id).Count());
            Assert.AreEqual(3, tmpFactory.GetAllBySectionId(_TestSections[1].Id).Count());
            Assert.AreEqual(1, tmpFactory.GetAllBySectionId(_TestSections[2].Id).Count());
        }

        [TestMethod]
        public void Question_GetAllUnusedBySectionId_ReturnsCorrectList()
        {
            QuestionFactory factory = new QuestionFactory();
            var tmp = factory.GetAllUnusedBySectionId(_TestSections[0].Id, _TestSite.Id).ToArray();
            Assert.AreEqual(1, tmp.Count());

            foreach (var s in _TestSiteQuestions)
            {
                s.Deleted = true;
            }
            _Context.SubmitChanges();
            tmp = factory.GetAllUnusedBySectionId(_TestSections[0].Id, _TestSite.Id).ToArray();
            Assert.AreEqual(_TestQuestions.Count(), tmp.Count());

        }
    }
}
